<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // ================================================================================
    // //属性简写
    // // 背景
    // var age = 18;
    // // DRY dont't repeat yourself
    // var user = {
    //     name: 'jay',
    //     // es5的写法
    //     // age: age,
    //     // 对象的属性名和值是一样的可以简写
    //     age,
    //     // 对象中的function都是重复代码，可以省略
    //     // sayHi: function () {
    //     //     console.log('你好');
    //     // }
    //     // 但是括号不能省
    //     sayHi() {
    //         console.log('你好');
    //     }
    // }
    // // 属性名表达式
    // var a = 'say'
    // var b = 'Hi'
    // user[a + b]()//你好
    // ---------------------------------------------------------------------------------------
    // // 对象属性名表达式
    // var a = 'age';
    // var user = {
    //     name: 'joLin',
    //     a: 18,//a:18
    //     [a]: 20,//age:20
    //     // 如果属性名表达式是一个对象，会被统一转换为[object Object]
    //     [user]:20,//[object Object]:20

    // }
    // console.log(user);
    // ---------------------------------------------------------------------------------------
    // 对象的扩展运算符...
    // var obj = {
    //     name: 'jay',
    //     age: '15',
    // }
    // var obj1 = {
    //     name: 'joLin',
    //     say() {
    //         console.log('你好');

    //     }
    // }
    // // 对象合并，同名属性会被覆盖，后面的会覆盖前面的
    // console.log({ ...obj, ...obj1 });
    // // 可以从对象中取出多个属性，也可以实现对象属性的删除
    // var { name, ...a } = obj
    // console.log(a);//age:15
    // // 实现对象的浅拷贝
    // console.log({...obj});

    // // 实际应用
    // // 扩展运算符可用于对象的默认值
    // var a = {
    //     name: '无',
    //     age: 0,
    //     sex: '男（默认）',
    //     say() {
    //         console.log(`你好'${this.name}'`);

    //     }
    // }
    // var user = {
    //     name: 'joLin',
    //     sex: '女',

    // }
    // var user1 = { ...a, ...user };
    // console.log(user1);
    // user1.say();
    // ================================================================================
    // 对象的新增方法
    // // Object.is()比较两个值是否相等
    // // 可以解决NaN不等于自身的问题，以及+0和-0相等的问题
    // console.log('a' === 'a');//true
    // console.log(Object.is('a', 'a'));//true
    // console.log({} == {});//false
    // console.log(Object.is({}, {}));//false
    // console.log(+0 === -0);//true
    // console.log(Object.is(+0, -0));//false
    // console.log(NaN === NaN);//false
    // console.log(Object.is(NaN, NaN));//true

    // ---------------------------------------------------------------------------------------
    // // Object.assign()
    // // 浅拷贝
    // // 第一个参数是目标对象，从第二个参数开始他是被合并的对象
    // var a = {
    //     name: '无',
    //     age: 0,
    //     sex: '男（默认）',
    //     say() {
    //         console.log(`你好'${this.name}'`);

    //     }
    // }
    // var b = {
    //     name: 'joLin',
    //     sex: '女',
    // }
    // // 把b合并到a中，会改变a,不会改变b
    // console.log(Object.assign(a, b));
    // console.log(a);
    // console.log(b);
    // // 把a和b合并到一个空对象中，不会改变a和b
    // console.log(Object.assign({}, a, b));
    // console.log(a);
    // console.log(b);

    // ---------------------------------------------------------------------------------------
    // Object.keys(),Object.values(),Object.entries()

    //  Object.keys()把对象中的属性名取出来放进一个数组中
    // var a = {
    //     name: '无',
    //     age: 0,
    //     sex: '男（默认）',
    //     say() {
    //         console.log(`你好'${this.name}'`);

    //     }
    // }
    // var b = {
    //     name: 'joLin',
    //     sex: '女',
    // }
    // console.log(Object.keys(a));//['name','age','sex','say']
    // console.log(Object.keys(b));//['name','sex']
    // // 在es6之前，对象的处理很不灵活，不可以像数组那样有很多方法，处理起来很灵活
    // // 对象之前只能使用for in循环，但是这个循环会把原型上的遍历出来，会出现意料之外的问题
    // Object.keys(a).forEach(item => {
    //     console.log(`key:${item},value:${a[item]}`);
    // })

    // // Object.values()把对象里的所有值取出来放入一个数组中
    // // 可以理解为是Object.keys()的一个补充
    // console.log(Object.values(a));
    // console.log(Object.values(b));




    // Object.entries() 把对象中的键名和键值取出来放进一个二维数组中
    // Object.fromEntries() 把一个二维数组转换成一个对象
    // var name = 'jay';
    // var age = 18;
    // var a = {
    //     name,
    //     age,
    //     say(){}
    // }
    // console.log(Object.entries(a));
    // Object.entries(a).forEach(item => {
    //     console.log(item);
    // })

    // ---------------------------------------------------------------------------------------
    // // Object.hasOwn()
    // // 第一个参数是要判断的对象，第二个参数是属性名
    // // 对象实例有一个hasOwnProperty（）方法
    // var obj = Object.create({ a: 1 });
    // obj.b = 2;
    // // 自有属性返回true，原型属性返回false
    // console.log(Object.hasOwn(obj, 'a'));//false
    // console.log(Object.hasOwn(obj, 'b'));//true


    // ================================================================================
    // 对象其他扩展方法
    // ---------------------------------------------------------------------------------------
    // Object.freeze()冻结对象
    // Object.isFrozen()判断一个对象是否被冻结
    // 冻结后的对象里的属性无法删除、修改也无法新增
    // vue中对于一些不需要也不会改变的对象，可以使用冻结方法，因为vue中，所有对象要增加的响应式会使用循环加递归劫持对象
    // var a = {
    //     name: 'jay'
    // }
    // Object.freeze(a)
    // a.age = 18
    // console.log(a.age);//undefined
    // console.log(a);
    // console.log(Object.isFrozen(a));//true



    // ---------------------------------------------------------------------------------------
    // Object.getPrototypeOf()获取原型对象
    // var s = Object.create({ age: 18 })
    // s.age = 20
    // console.log(s);//20
    // // 类似于__proto__
    // console.log(Object.getPrototypeOf(s));//18


    // Object.seal()密封
    // Object.isSealed()判断一个对象是都被密封
    // 不能添加属性，不能删除现有属性
    // 可以修改和查看现有属性
    // var a = {
    //     age: 18
    // };
    // Object.seal(a);
    // a.name = 'jay';
    // a.age = 20;
    // console.log(a);//age:20
    // console.log(Object.isSealed(a));//true


    // Object.preventExtensions（）
    // 防止新属性被添加到对象中
    // var a = { age: 18 };
    // var b = { name: 'joLin' }
    // Object.preventExtensions(a)
    // a.name = 'jay'
    // console.log(a)//age:18


    // Object.isExtensible()
    // 静态方法判断一个对象是否是可扩展的
    // var a = { age: 18 };
    // console.log(Object.isExtensible(a));//true
    // // 冻结
    // Object.freeze(a)
    // console.log(Object.isExtensible(a));//false
    // // 密封
    // Object.seal(a)
    // console.log(Object.isExtensible(a));//false


    // Object.defineProperty()
    // 参数一被劫持的目标对象
    // 参数二目标对象的一个属性名（字符串）
    // 参数三配置项:
    // 1.value：属性的值
    // 2.writable：一个布尔值，表示属性值是否可写
    // 3.enumerable：一个布尔值，表示属性是否可枚举（即是否会出现在对象的属性迭代中）
    // 4.configurable：一个布尔值，表示属性描述符是否可以改变，或者属性是否可以从对象中删除
    // 5.get(getter)：一个函数，获取值（访问器）
    // 6.set(setter)：一个函数，设置值（设置器）
    // 注意：writable和set只能用一个，value和get只能用一个
    var a = { age: 18, }
    // 把对象的属性缓存一下
    var name = 'joLin'
    Object.defineProperty(a, 'name', {
        // 属性的值
        // value: 'jay',
        // 是否可修改（默认为false）
        // writable: true,
        // 是否可遍历出来（默认为false）
        enumerable: true,
        // 是否可被删除（默认为false）
        configurable: true,
        // 当访问name属性时调用的函数
        get() {
            // 在vue2中在这里会收集使用到该变量的所有位置，保存起来
            console.log('get:');
            return 'jay'; // 这里返回的值将作为属性的值
        },
        // 当设置name属性的值时调用的函数
        set(newValue) {
            // 直接修改被劫持的属性值会造成死循环，引起内存泄漏
            // a.name = newValue
            name = newValue
            // vue2修改数据后会通知所有使用到该变量位置更新变量，并且不更新
            console.log('set: ' + newValue);
        },
    })
    // a.age = 20

    // // writable
    // a.name = 'joLin'
    // console.log(a);

    // // enumerable
    // for (var key in a) {
    //     console.log(key, a[key]);
    // }

    // // configurable
    // delete a.name
    // console.log(a);


    // // get
    // console.log(a.name);


    // // set
    // a.name = 'jo';
    // console.log(a);












</script>

</html>